drizzlefandomcom_it-20200215-history
Proposta per un nuovo protocollo di test (TP)
Obiettivi * Renderlo più modulare * Renderlo più leggibile * Rendere più facile per la gente contribuire * Fornire una miglior copertura (rifacendo un build con un piano per il coverage, bug e use cases) Requisiti Ci sono almeno tre aree che hanno bisogno di testing. Ognuna dipende e poggia sulle aree elencate successivamente. #Test di comandi SQL #Test delle configurazioni, necessaria per testare i comandi # Test dei comandi del sistema operativo, compreso generare e far funzionare le varie configurazioni Proposta Il TP (Test Protocol) di Drizzle servirebbe a rimpiazzare mysql-test. Una nuova sintassi per i test, che segue la sintassi tradizionale di Unit Test (per esempio suite di test cases ognuna contenente un certo numero di test). I test sono formati dalle condizioni, il setup, il teardown, le operazioni, le assertion e i risultati, tutto in un unico file (*). Il TP è una sintassi agnostica leggibile dagli umani. C'è bisogno di traduzioni del TP in un linguaggio (esempi: lua, python, perl etc etc) C'è bisogno di una infrastruttura di base che possa interagire con un driver nativo, eseguire statement e comandi del sistema, nonchè fornire accesso ai risultati più vicini al livello di protocollo. Un'implementazione potrebbe essere: * Infrastruttura A C con motore DPM embedded (proxy già funzionante con supporto c/lua). * L'uso di DPM che parli il protocollo e intefri il supporto ai risultati ad un livello più dettagliato (suggerisce di scegliere Lua) * La scelta di un linguaggio per i test è Lua, con una metasintassi semplificata per gli esseri umani. Sintassi TP Initialize: master_only_simple() SetUp: USE test; DROP TABLE IF EXISTS t1; TearDown: DROP TABLE IF EXISTS t1; Test: SELECT 1 AS col rows=1 md5=.... Test: SELECT 2 AS col rows=1 md5=999999999999999 Anche se c'è bisogno di parole chiave (Configuration,SetUp,TearDown,Test), ':' e l'indentazione sono assolutamente opzionali per ora (è in stile Python, almeno per quanto riguarda la leggibilità) e aperti per l'input. Domanda: identifichiamo la sintassi SQL in modo da sapere cosa è SQL e cosa è TP? Esempio: {SELECT 1} Dettagli sui vari blocchi Initialize Syntax: Initialize: Lancia una serie di comandi per TestCase e generalmente include una chiamata a un test case (esempio: master_only_simple) che crea le istanze necessarie e le variabili globali di connessione, che corrispondono ai nomi rappresentati. Può supportare il successo di un TestCase precedente (come prerequisito ad esempio). Tutte le direttive globali dei TestCase (per esempio expectnoerror # Questo produce un noerror implicito dopo ogni istruzione SQL) Instances è una mappa delle chiavi e di tutte le impostazioni etc esempio: m1, m2, s1, s2, s3, etc m1 = {host:localhost,port=9900, ...} connections è una mappa delle connessioni alle istanze date esempio c1, c2, c3 etc c1 = {instance=m1,user=root,password=,schema=x} Per default Insance e Connection si specificano globalmente, o forse il primo nella mappa è di default instance=m1 connection=c1 Questo livello di istanze e connessioni è necessario per testare la replica, la scalabilità e la concorrenza per esempio. Altre opzioni da considerare possono essere comandi dopo ogni istruzione SQL. Un esempio potrebbe essere la sostituzione o l'astrazione di un nome di storage engine (InnoDB, MyISAM) etc. SetUp Syntax: SetUp Comandi da eseguire prima di ogni test. TearDown Sytnax: TearDown Comandi da eseguire dopo ogni test. Test Syntax: Test timeout=x testname connection=? # Support for concurrency testing rows=N noerror error NNNN La versione leggibile dagli esseri umani è più una macro. The human readable version is more a macro to expanded language syntax In qualunque momento tu voglia fare una cosa specifica, embedda semplicemente la sintassi del linguaggio (esempio lua) {SELECT NOW() AS date1} sleep(0.001) data1=rows11 {SELECT NOW() AS data2} data1 != rows11 esempio SELECT 1 is rs=SQL("SELECT 1") rows=N is assertEquals(rs.rows, N) noerror is assertNull(c.error) error NNNN is assertEquals(c.error, NNNN) Output Il minimo di cui hai bisogno nell'output è: testname (999 ms) pass|fail Non ho speso tempo nel concentrarmi sul formato dell'output, sembra che siamo d'accordo nell'utilizzare TAP -http://en.wikipedia.org/wiki/Test_Anything_Protocol Fornire l'infrastruttura espone le informazioni elencate in 'Variabili dell'Infrastruttura dei Test' e un livello di reporting è possibile. Variabili dell'Infrastruttura dei Test Vorrei che le seguenti variabili fossero disponibili per il TP e che con tutte queste variabili si potesse produrre un report. # Struttura Globale RunResult SuccessFail totalTime NoSuites NoTestCases NoTests SuiteResult[] #Per Ogni Suite Eseguita SuiteResult SuiteName NoTestsCases SuccessFail totalTime TestCaseResult[] #Per Ogni TestCase Eseguito TestCaseResult testCaseName NoTests SuccessFail totalTime TestResult[] #Per Ogni Test Eseguito TestResult testName (default: testNNNN) SuccesFail time Creare i test * Un buon numero di test di copertura del codice (475 test, 200mila righe di test case) può facilmente essere rigenerato (lavoro che ho fatto precedentemente) * Il parsing dei test case esistenti di MySQL per producce dei test di base (esempio: Test: SQL,rows=,md5 si possono produrre facilmente) * La pagina web per inviare i test, semplicemente copia-incolla l'SQL (con i risultati), opzionalmente i dati. Script da parsare nel TP di Drizzle. Implementazione La scelta del linguaggio non è ancora stata fatta. Potrebbe facilmente essere Perl, Python o Lua per esempio, il seguente esempio è con Lua. Questa decisione verrà presa da chi farà il lavoro. Al Drizzle Bof alla OSON, è stato proposto che si possa disporre di diversi linguaggi, il migliore sopravviverà. Scegliere un interprete per il Test Protocol C'è bisogno di poter incapsulare la sintassi del linguaggio nei test case. Rasformare il linguaggio umano in un linguaggio di programmazione. Esecuzione. Un'opzione è Lua. Fornisce una sintassi per le unità di test (come mostrato sotto) che è più semplice rispetto agli altri linguaggi. Il codice da integrare è piccolo. Pluggandolo nel dpm proxy, raggiungi importanti obiettivi dei test accedendo ai risultati del protocollo. dpm proxy: http://consoleninja.net/code/dpm/README.html Sintassi di Lua per le unità di test Il Testing Protocol deve passare per una traduzione dal linguaggio facilmente leggibile dagli esseri umani a Lua. Una possibile traduzione potrebbe essere simile alla seguente. Notare che questa sintassi non è stata testata Le unità di test di Lua sono simili a quelle di Java. Documentazione: http://lua-users.org/wiki/UnitTesting -- L'unità di test parte require('luaunit') TestCase = {} --classe function TestCase:setUp() --questa funzione è eseguita prima di ogni test end function TestCase:tearDown() -- questa funzione è eseguita dopo ogni test end function TestCase:test1() rs = SQL("SELECT 1") assertEquals( rs.rows, 1 ) assertEquals( md5(rs.???, "c4c43a9efab8cc70ee1fd9580693e1f2") assertEquals( type(rs.rows11), 'number' ) assertEquals( rs.rows11, 1) end luaUnit:run() Domande & Risposte D: Come faccio a testare query non deterministiche? (esempio: EXPLAIN per Innodb) R: Le tue assertion non saranno una comparazione byte per byte (che si può fare con md5), puoi ricorrere a dei particolari pattern matching Storia La Test Suite di MySQL Il vecchio modo t/select.test ------ SELECT 1 AS col ------ r/select.result ------ col 1 ------ Problemi * Due file per ogni test * Di conseguenza le dimensioni crescono, i file dei risultati crescono * Supporto debole per i differenti storage engine * Ordinamento arbitratio non supportato (un risultato degli engine) * Valori non deterministici non supportati (esempio CURDATE()) * Molti tipi unici di comandi aggiuntivi con sintassi -- Come funziona l'altra unità di test? Usiamo junit (www.junit.org) come esempio per il test delle unità e la suite di tool che fornisce molti layer di test. * Una Suita comprende uno o più Test Cases * Un Test Case (file unico) ha uno o più test (@Test è l'annotazione usata) * Un Test Case può avere un setUp opzionare (@Before) e un tearDown (@After) che vengono eseguiti per ogni test che fa parte del Test Case * Ogni test ha un certo numero di comandi e un certo numero di assertion (tutte nel test), esempio: AssertEquals(x,1), AssertNotNull(var) etc * Esistono delle opzioni aggiuntive, per esempio per il timeout, la gestione degli errori, etc Cosa occorre supportare * Gestione delle connessioni * Concorrenza * Ordinamento arbitrario (esempio: i risultati sono diversi per i diversi engine, ma contengono le stesse righe) * Astrazione dei pattern (es: ENGINE=MyISAM|InnoDB Il vecchio modo: let $ENGINE=`select variable_value from information_schema.global_variables where variable_name='STORAGE_ENGINE'`; --replace_result $ENGINE ENGINE Alcuni problemi Generalmente non teniamo tutto l'output dei risultati dei test. Se per esempio c'è una differenza con md5, e certi test fanno solo delle altre asserzioni che risultano positive, abbiamo perso i dati dei risultati sottostanti. Forse dovremmo tenere una versione serializzata degli effettivi risultati dei test per la comparazione. Ci può essere bisogno di un file testcase.data per ogni testcase. en:Proposed Testing Protocol Category:Implementazioni future